package frame.options.simulation.results.physicalNetworks.graphical;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;

import javax.swing.Icon;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JTabbedPane;

import model.components.links.link.BandwidthBackupFlag;
import model.components.links.link.Link;
import model.components.links.link.VirtualLink;
import model.components.links.link.PhysicalLink;
import model.components.networks.network.VirtualNetwork;
import model.components.networks.network.PhysicalNetwork;
import model.components.nodes.node.VirtualNode;
import model.components.nodes.node.PhysicalNode;
import model.components.nodes.node.Node;
import model.components.nodes.node.VirtualRouter;
import model.components.nodes.node.PhysicalRouter;
import model.components.nodes.node.VirtualServer;
import model.components.nodes.node.PhysicalServer;
import model.components.nodes.node.VirtualSwitch;
import model.components.nodes.node.PhysicalSwitch;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.AbstractPopupGraphMousePlugin;
import frame.options.simulation.results.ResultsFrame;
import frame.options.simulation.results.virtualNetworks.graphical.VirtualNetworkVisualizationViewersPanel;

public class PhysicalNetworkPopupGraphMousePlugin extends AbstractPopupGraphMousePlugin implements ActionListener
{
	private PhysicalNode physicalNode;
	public PhysicalNode getPhysicalNode(){ return physicalNode; }
	public void setPhysicalNode( PhysicalNode physicalNode ){ this.physicalNode = physicalNode; }
	
	private JPopupMenu physicalNodePopupMenu;
	public JPopupMenu getPhysicalNodePopupMenu(){ return physicalNodePopupMenu; }
	public void setPhysicalNodePopupMenu( JPopupMenu physicalNodePopupMenu ){ this.physicalNodePopupMenu = physicalNodePopupMenu; }
	
	private PhysicalLink physicalLink;
	public PhysicalLink getPhysicalLink(){ return physicalLink; }
	public void getPhysicalLink( PhysicalLink physicalLink ){ this.physicalLink = physicalLink; }
	
	private JPopupMenu physicalLinkPopupMenu;
	public JPopupMenu getPhysicalLinkPopupMenu(){ return physicalLinkPopupMenu; }
	public void setPhysicalLinkPopupMenu( JPopupMenu physicalLinkPopupMenu ){ this.physicalLinkPopupMenu = physicalLinkPopupMenu; }
	
	private ResultsFrame resultsFrame;
	public ResultsFrame getResultsFrame(){ return resultsFrame; }
	public void setResultsFrame( ResultsFrame resultsFrame ){ this.resultsFrame = resultsFrame; }
	
	public PhysicalNetworkPopupGraphMousePlugin( ResultsFrame resultsFrame )
    {
    	super( InputEvent.BUTTON3_MASK );
    	
    	this.setResultsFrame( resultsFrame );
    	
    	this.setPhysicalNodePopupMenu( new JPopupMenu() );
    	this.setPhysicalLinkPopupMenu( new JPopupMenu() );
    }
    
    @Override
	@SuppressWarnings("unchecked")
    protected void handlePopup( MouseEvent mouseEvent )
    {
    	VisualizationViewer< Node, Link > visualizationViewer = (VisualizationViewer< Node, Link >) mouseEvent.getSource();
        
    	PhysicalNode physicalNode = (PhysicalNode) visualizationViewer.getPickSupport().getVertex( visualizationViewer.getGraphLayout(), mouseEvent.getPoint().getX(), mouseEvent.getPoint().getY() );
    	this.setPhysicalNode( physicalNode );
    	
        PhysicalLink physicalLink = (PhysicalLink) visualizationViewer.getPickSupport().getEdge( visualizationViewer.getGraphLayout(), mouseEvent.getPoint().getX(), mouseEvent.getPoint().getY() );
        this.getPhysicalLink( physicalLink );
        
    	if( physicalNode != null )
    	{
    		this.updatePhysicalNodePopupMenu( physicalNode );
    		this.getPhysicalNodePopupMenu().show( visualizationViewer, mouseEvent.getX(), mouseEvent.getY() );
    	}
    	else if( physicalLink != null )	
    	{
    		this.updatePhysicalLinkPopupMenu( physicalLink );
    		this.getPhysicalLinkPopupMenu().show( visualizationViewer, mouseEvent.getX(), mouseEvent.getY() );
    	}
    }
    
    private void updatePhysicalNodePopupMenu( PhysicalNode physicalNode )
    {
    	this.getPhysicalNodePopupMenu().removeAll();
		this.getPhysicalNodePopupMenu().add( this.physicalNodeMenuItem( physicalNode ) );
		
		for( VirtualNode virtualNode: physicalNode.getVirtualNodes() )
		{
			this.getPhysicalNodePopupMenu().addSeparator();
			this.getPhysicalNodePopupMenu().add( this.virtualNodeMenuItem( virtualNode ) );
		}
    }
    private JMenuItem physicalNodeMenuItem( PhysicalNode physicalNode )
    {
    	Icon menuItemIcon = null;
    	
		if( physicalNode.isSelected() )
			menuItemIcon = physicalNode.getGreenIcon();
		
		else if( physicalNode.getVirtualNodes().size() != 0 )
			menuItemIcon = physicalNode.getYellowIcon();
		
		else
			menuItemIcon = physicalNode.getGreyIcon();
    	
    	String menuItemText = null;
		
    	if( physicalNode instanceof PhysicalRouter || physicalNode instanceof PhysicalSwitch )
    		menuItemText = "<html><b>NODE:</b> " + physicalNode.getName()+ "<br><b>NETWORK:</b> " + physicalNode.getNetworkName() + "<br><b>OPERATING SYSTEM:</b> " + physicalNode.getOperatingSystem() + "<br><b>VIRTUAL ENVIRONMENT:</b> " + physicalNode.getVirtualEnvironment() + "<br><b>CPU:</b> " + physicalNode.getCpu() + "<br><b>MEMORY:</b> " + physicalNode.getMemory() + "</html>";
    	
    	else if( physicalNode instanceof PhysicalServer )
    		menuItemText = "<html><b>NODE:</b> " + physicalNode.getName() + "<br><b>NETWORK:</b> " + physicalNode.getNetworkName() + "<br><b>OPERATING SYSTEM:</b> " + physicalNode.getOperatingSystem() + "<br><b>VIRTUAL ENVIRONMENT:</b> " + physicalNode.getVirtualEnvironment() + "<br><b>CPU:</b> " + physicalNode.getCpu() + "<br><b>MEMORY:</b> " + physicalNode.getMemory() + "<br><b>DISK SPACE:</b> " + physicalNode.getDiskSpace() + "</html>";
    	
    	JMenuItem physicalNodeMenuItem = new JMenuItem();
    	physicalNodeMenuItem.setIcon( menuItemIcon );
    	physicalNodeMenuItem.setText( menuItemText );
    	physicalNodeMenuItem.addActionListener( this );
    	
    	return physicalNodeMenuItem;
    }
    private JMenuItem virtualNodeMenuItem( VirtualNode virtualNode )
    {
    	Icon menuItemIcon = null;
    	
		if( virtualNode.isSelected() )
			menuItemIcon = virtualNode.getGreenIcon();
		else
			menuItemIcon = virtualNode.getYellowIcon();
    	
    	String menuItemText = null;
			
		if( virtualNode instanceof VirtualRouter || virtualNode instanceof VirtualSwitch )
			menuItemText = "<html><b>NODE:</b> " + virtualNode.getName() + "<br><b>NETWORK:</b> " + virtualNode.getNetworkName() + "<br><b>OPERATING SYSTEM:</b> " + virtualNode.getOperatingSystem() + "<br><b>VIRTUAL ENVIRONMENT:</b> " + virtualNode.getVirtualEnvironment() + "<br><b>CPU:</b> " + virtualNode.getCpu() + "<br><b>MEMORY:</b> " + virtualNode.getMemory() + "</html>";
		
		else if( virtualNode instanceof VirtualServer )
			menuItemText = "<html><b>NODE:</b> " + virtualNode.getName() + "<br><b>NETWORK:</b> " + virtualNode.getNetworkName() + "<br><b>OPERATING SYSTEM:</b> " + virtualNode.getOperatingSystem() + "<br><b>VIRTUAL ENVIRONMENT:</b> " + virtualNode.getVirtualEnvironment() + "<br><b>CPU:</b> " + virtualNode.getCpu() + "<br><b>MEMORY:</b> " + virtualNode.getMemory() + "<br><b>DISK SPACE:</b> " + virtualNode.getDiskSpace() + "</html>";
        
		JMenuItem virtualNodeMenuItem = new JMenuItem();
		virtualNodeMenuItem.setName( virtualNode.getName() + "-" +  virtualNode.getNetworkName() );
		virtualNodeMenuItem.setIcon( menuItemIcon );
		virtualNodeMenuItem.setText( menuItemText );
		virtualNodeMenuItem.addActionListener( this );
        	
		return virtualNodeMenuItem;
    }
	
    private void updatePhysicalLinkPopupMenu( PhysicalLink physicalLink )
    {
		this.getPhysicalLinkPopupMenu().removeAll();
		this.getPhysicalLinkPopupMenu().add( this.physicalLinkMenuItem( physicalLink ) );
		
    	if( physicalLink.getVirtualLinksBandwidthsBackupFlags().size() > 0 )
    	{
	    	Iterator< Entry< VirtualLink, BandwidthBackupFlag > > virtualLinksBandwidthsBackupFlagsIterator = physicalLink.getVirtualLinksBandwidthsBackupFlags().entrySet().iterator();
			
			while( virtualLinksBandwidthsBackupFlagsIterator.hasNext() )
			{
				this.getPhysicalLinkPopupMenu().addSeparator();
				this.getPhysicalLinkPopupMenu().add( this.virtualLinkMenuItem( virtualLinksBandwidthsBackupFlagsIterator.next() ) );
			}
    	}
    }
    private JMenuItem physicalLinkMenuItem( PhysicalLink physicalLink )
    {
		Node firstNode = physicalLink.getFirstNode();
    	Node secondNode = physicalLink.getSecondNode();
		
    	JMenuItem physicalLinkMenuItem = new JMenuItem();
    	physicalLinkMenuItem.setText( "<html><b>LINK:</b> " + firstNode.getName() + " <b>to</b> " + secondNode.getName() + "<br><b>NETWORK:</b> " + physicalLink.getNetworkName() +  "<br><b>BANDWIDTH: </b> " + physicalLink.getBandwidth() + "</html>" );
    	physicalLinkMenuItem.setIcon( physicalLink.getIcon() );
    	physicalLinkMenuItem.addActionListener( this );
    	
    	return physicalLinkMenuItem;
    }
    private JMenuItem virtualLinkMenuItem( Entry< VirtualLink, BandwidthBackupFlag > virtualLinkBandwidthBackupFlag )
    {
    	VirtualLink virtualLink = virtualLinkBandwidthBackupFlag.getKey();
		Node firstNode = virtualLink.getFirstNode();
		Node secondNode = virtualLink.getSecondNode();
		
		JMenuItem virtualLinkMenuItem = new JMenuItem();
		virtualLinkMenuItem.setIcon( virtualLink.getIcon() );
		virtualLinkMenuItem.setName( virtualLink.getName() + "-" + virtualLink.getNetworkName() );
    	
		if( virtualLinkBandwidthBackupFlag.getValue().getBackupFlag() == 0 )
			virtualLinkMenuItem.setText( "<html><b>LINK:</b> " + firstNode.getName() + " <b>to</b> " + secondNode.getName() + "<br><b>NETWORK:</b> " + virtualLink.getNetworkName() + "<br><b>BANDWIDTH:</b> " + virtualLink.getBandwidth() + " (<FONT COLOR=\"green\">" + virtualLinkBandwidthBackupFlag.getValue().getBandwidth() + " Normal</FONT>)" + "<br><b>TYPE:</b> " + virtualLink.getType() + "</html>" );
		
		else if( virtualLinkBandwidthBackupFlag.getValue().getBackupFlag() == 1 )
			virtualLinkMenuItem.setText( "<html><b>LINK:</b> " + firstNode.getName() + " <b>to</b> " + secondNode.getName() + "<br><b>NETWORK:</b> " + virtualLink.getNetworkName() + "<br><b>BANDWIDTH:</b> " + virtualLink.getBandwidth() + " (<FONT COLOR=\"green\">" + virtualLinkBandwidthBackupFlag.getValue().getBandwidth() + " Backup</FONT>)" + "<br><b>TYPE:</b> " + virtualLink.getType() + "</html>" );
		
		virtualLinkMenuItem.addActionListener( this );
    	
		return virtualLinkMenuItem;
    }
    
    @Override
	public void actionPerformed( ActionEvent actionEvent )
	{
		this.deselectPhysicalNetworks();
		this.deselectVirtualNetworks();
		
		PhysicalNode physicalNode = this.getPhysicalNode();
		PhysicalLink physicalLink = this.getPhysicalLink();
		String menuItemName = ( (JMenuItem) actionEvent.getSource() ).getName();
		
		if( physicalNode != null )
		{
			physicalNode.setSelected( true );
			
			if( menuItemName != null )
			{
				String virtualNodeName = menuItemName.split( "-" )[ 0 ];
				String virtualNodeNetworkName = menuItemName.split( "-" )[ 1 ];
				
				VirtualNode mappedVirtualNode = null;
				
				for( VirtualNode virtualNode: physicalNode.getVirtualNodes() )
					if( virtualNode.getName().equals( menuItemName.split( "-" )[ 0 ] ) && virtualNode.getNetworkName().equals( menuItemName.split( "-" )[ 1 ] ) )
					{
						mappedVirtualNode = virtualNode;
						break;
					}
				
				VirtualNetwork virtualNetwork = this.virtualNetwork( mappedVirtualNode.getNetworkName(), mappedVirtualNode.getTimeStamp() );
					
				if( virtualNetwork.getTimeStamp() == mappedVirtualNode.getTimeStamp() )
					for( VirtualNode virtualNode: virtualNetwork.getVirtualNodes() )
						if( virtualNode.getNumber() == mappedVirtualNode.getNumber() )
						{
							mappedVirtualNode.setSelected( true );
								
							virtualNode.setSelected( true );
							virtualNode.getPhysicalNode().setSelected( true );
							break;
						}
			}
		}
		else if( physicalLink != null )
		{
			physicalLink.setSelected( true );
			physicalLink.getFirstNode().setSelected( true );
			physicalLink.getSecondNode().setSelected( true );
			
			if( menuItemName != null )
			{
				String virtualLinkName = menuItemName.split( "-" )[ 0 ];
				String virtualLinkNetworkName = menuItemName.split( "-" )[ 1 ];
				
				Iterator< Entry< VirtualLink, BandwidthBackupFlag > > iterator = physicalLink.getVirtualLinksBandwidthsBackupFlags().entrySet().iterator(); 
				VirtualLink mappedVirtualLink = null;
				
				while( iterator.hasNext() )
				{
					mappedVirtualLink = iterator.next().getKey();
					
					if( mappedVirtualLink.getNetworkName().equals( virtualLinkNetworkName ) )
						break;
				}
				
				VirtualNetwork virtualNetwork = this.virtualNetwork( mappedVirtualLink.getNetworkName() , mappedVirtualLink.getTimeStamp() );
				
				for( VirtualLink virtualLink: virtualNetwork.getVirtualLinks() )
					if( virtualLink.getName().equals( virtualLinkName ) && virtualLink.getNetworkName().equals( virtualLinkNetworkName ) )
					{
						virtualLink.setSelected( true );
						virtualLink.getFirstNode().setSelected( true );
						virtualLink.getSecondNode().setSelected( true );
						break;
					}
			}
		}
		
		this.getResultsFrame().getPhysicalNetworksVisualizationViewersPanelsTabbedPane().repaint();
		this.getResultsFrame().getVirtualNetworksVisualizationViewersPanelsTabbedPane().repaint();
	}
    private void deselectPhysicalNetworks()
	{
		List< PhysicalNetworkVisualizationViewersPanel > physicalNetworkVisualizationViewersPanels = this.getResultsFrame().getPhysicalNetworksVisualizationViewersPanels();
		
		for( int i = 0; i < physicalNetworkVisualizationViewersPanels.size(); i++ )
		{
			List< PhysicalNetwork > physicalNetworks = physicalNetworkVisualizationViewersPanels.get( i ).getPhysicalNetworks();
			
			for( int j = 0; j < physicalNetworks.size(); j++ )
			{
				PhysicalNetwork physicalNetwork = physicalNetworks.get( j );
				
				for( PhysicalNode physicalNode: physicalNetwork.getPhysicalNodes() )
				{
					physicalNode.setSelected( false );
					
					for( VirtualNode virtualNode: physicalNode.getVirtualNodes() )
						virtualNode.setSelected( false );
				}
				
				for( PhysicalLink physicalLink: physicalNetwork.getPhysicalLinks() )
					physicalLink.setSelected( false );
			}
		}
	}
    private void deselectVirtualNetworks()
	{
		List< VirtualNetworkVisualizationViewersPanel > virtualNetworkVisualizationViewersPanels = this.getResultsFrame().getVirtualNetworksVisualizationViewersPanels();
		
		for( int i = 0; i < virtualNetworkVisualizationViewersPanels.size(); i++ )
		{
			List< VirtualNetwork > virtualNetworks = virtualNetworkVisualizationViewersPanels.get( i ).getVirtualNetworks();
			
			for( int j = 0; j < virtualNetworks.size(); j++ )
			{
				VirtualNetwork virtualNetwork = virtualNetworks.get( j );
				
				for( VirtualNode virtualNode: virtualNetwork.getVirtualNodes() )
					virtualNode.setSelected( false );
				
				for( VirtualLink virtualLink: virtualNetwork.getVirtualLinks() )
					virtualLink.setSelected( false );
			}
		}
	}
    private VirtualNetwork virtualNetwork( String virtualNetworkName, int timeInstant )
	{
		JTabbedPane virtualNetworksVisualizationViewersTabbedPane = this.getResultsFrame().getVirtualNetworksVisualizationViewersPanelsTabbedPane();
		int indexOfTab = virtualNetworksVisualizationViewersTabbedPane.indexOfTab( virtualNetworkName );
		virtualNetworksVisualizationViewersTabbedPane.setSelectedIndex( indexOfTab );
		
		VirtualNetworkVisualizationViewersPanel virtualNetworkVisualizationViewersPanel = this.getResultsFrame().getVirtualNetworksVisualizationViewersPanels().get( indexOfTab );
		List< VirtualNetwork > virtualNetworks = virtualNetworkVisualizationViewersPanel.getVirtualNetworks();
		
		for( int i = 0; i < virtualNetworks.size(); i++ )
			if( virtualNetworks.get( i ).getTimeStamp() == timeInstant )
			{
				virtualNetworkVisualizationViewersPanel.putValueSliderss( i );
				return virtualNetworks.get( i );
			}
		
		return null;
	}

}
